home *** CD-ROM | disk | FTP | other *** search
- Frequently Asked Questions (FAQS);faqs.354
-
-
-
- 1969 Anthony Hearn and Martin Griss define Standard Lisp to
- port REDUCE, a symbolic algebra system, to a variety
- of architectures.
-
- late 70s Macsyma group at MIT developed NIL (New Implementation
- of Lisp), a Lisp for the VAX.
-
- Stanford and Lawrence Livermore National Laboratory
- develop S-1 Lisp for the Mark IIA supercomputer.
-
- Franz Lisp (dialect of MacLisp) runs on stock-hardware
- Unix machines.
-
- Gerald J. Sussman and Guy L. Steele developed Scheme,
- a simple dialect of Lisp with lexical scoping and
- lexical closures, continuations as first-class objects,
- and a simplified syntax (i.e., only one binding per symbol).
-
- Advent of object-oriented programming concepts in Lisp.
- Flavors was developed at MIT for the Lisp machine,
- and LOOPS (Lisp Object Oriented Programming System) was
- developed at Xerox.
-
- early 80s Development of SPICE-Lisp at CMU, a dialect of MacLisp
- designed to run on the Scientific Personal Integrated
- Computing Environment (SPICE) workstation.
-
- 1980 First biannual ACM Lisp and Functional Programming Conf.
-
- 1981 PSL (Portable Standard Lisp) runs on a variety of platforms.
-
- 1981+ Lisp Machines from Xerox, LMI (Lisp Machines Inc)
- and Symbolics available commercially.
-
- April 1981 Grass roots definition of Common Lisp as a description
- of the common aspects of the family of languages (Lisp
- Machine Lisp, MacLisp, NIL, S-1 Lisp, Spice Lisp, Scheme).
-
-
- 1984 Publication of CLtL1. Common Lisp becomes a de facto
- standard.
-
- 1986 X3J13 forms to produce a draft for an ANSI Common Lisp
- standard.
-
- 1987 Lisp Pointers commences publication.
-
- 1990 Steele publishes CLtL2 which offers a snapshot of
- work in progress by X3J13. (Unlike CLtL1, CLtL2
- was NOT an output of the standards process and was
- not intended to become a de facto standard. Read
- the Second Edition Preface for further explanation
- of this important issue.) Includes CLOS,
- conditions, pretty printing and iteration facilities.
-
- 1992 X3J13 creates a draft proposed American National
- Standard for Common Lisp. This document is the
- first official successor to CLtL1.
-
- [Note: This summary is based primarily upon the History section of the
- draft ANSI specification. More detail and references can be obtained from
- that document. See [1-5] for information on obtaining a copy.]
- ----------------------------------------------------------------
- [2-14] How do I find the argument list of a function?
- How do I get the function name from a function object?
-
- There is no standard way to find the argument list of a function,
- since implementations are not required to save this information.
- However, many implementations do remember argument information, and
- usually have a function that returns the lambda list. Here are the
- commands from some Lisp implementations:
-
- Lucid: arglist
- Allegro: excl::arglist
- Symbolics: arglist
-
- CMU Common Lisp, new compiler:
- #+(and :CMU :new-compiler)
- (defun arglist (name)
- (let* ((function (symbol-function name))
- (stype (system:%primitive get-vector-subtype function)))
- (when (eql stype system:%function-entry-subtype)
- (cadr (system:%primitive header-ref function
- system:%function-entry-type-slot)))))
-
- If you're interested in the number of required arguments you could use
-
- (defun required-arguments (name)
- (or (position-if #'(lambda (x) (member x lambda-list-keywords))
- (arglist name))
- (length (arglist name))))
-
- To extract the function name from the function object, as in
- (function-name #'car) ==> 'car
- use the following vendor-dependent functions:
-
- Symbolics: (si::compiled-function-name <fn>)
- Lucid: (sys::procedure-ref <fn> SYS:PROCEDURE-SYMBOL)
- Allegro: (Xref::object-to-function-name <fn>)
- CMU CL: (kernel:%function-header-name <fn>)
- AKCL: (system::compiled-function-name <fn>)
- MCL: (ccl::function-name <fn>)
-
- ----------------------------------------------------------------
- [2-15] How can I have two Lisp processes communicate via unix sockets?
-
- CLX uses Unix sockets to communicate with the X window server. Look at
- the following files from the CLX distribution for a good example of
- using Unix sockets from Lisp:
- defsystem.lisp Lucid, AKCL, IBCL, CMU.
- socket.c, sockcl.lisp AKCL, IBCL
- excldep.lisp Franz Allegro CL
- You will need the "socket.o" files which come with Lucid and Allegro.
- To obtain CLX, see the entry for CLX in the answer to question [6-5].
-
- See the file lisp-sockets.text in the Lisp Utilities repository
- described in the answer to question [6-1].
-
- ----------------------------------------------------------------
-
- ;;; *EOF*
- Xref: bloom-picayune.mit.edu comp.lang.lisp:8751 news.answers:4561
- Path: bloom-picayune.mit.edu!enterpoop.mit.edu!spool.mu.edu!uunet!ogicse!das-news.harvard.edu!cantaloupe.srv.cs.cmu.edu!crabapple.srv.cs.cmu.edu!mkant
- From: mkant+@cs.cmu.edu (Mark Kantrowitz)
- Newsgroups: comp.lang.lisp,news.answers
- Subject: FAQ: Lisp Frequently Asked Questions 3/6 [Monthly posting]
- Summary: Common Pitfalls
- Message-ID: <lisp-faq-3.text_724237304@cs.cmu.edu>
- Date: 13 Dec 92 09:02:09 GMT
- Article-I.D.: cs.lisp-faq-3.text_724237304
- Expires: Tue, 26 Jan 1993 09:01:44 GMT
- Sender: news@cs.cmu.edu (Usenet News System)
- Reply-To: lisp-faq@think.com
- Followup-To: poster
- Organization: School of Computer Science, Carnegie Mellon
- Lines: 707
- Approved: news-answers-request@MIT.Edu
- Supersedes: <lisp-faq-3.text_721645325@cs.cmu.edu>
- Nntp-Posting-Host: a.gp.cs.cmu.edu
-
- Archive-name: lisp-faq/part3
- Last-Modified: Thu Nov 5 19:30:40 1992 by Mark Kantrowitz
- Version: 1.27
-
- ;;; ****************************************************************
- ;;; Answers to Frequently Asked Questions about Lisp ***************
- ;;; ****************************************************************
- ;;; Written by Mark Kantrowitz and Barry Margolin
- ;;; lisp-faq-3.text -- 32488 bytes
-
- This post contains Part 3 of the Lisp FAQ.
-
- If you think of questions that are appropriate for this FAQ, or would
- like to improve an answer, please send email to us at lisp-faq@think.com.
-
- This section contains a list of common pitfalls. Pitfalls are aspects
- of Common Lisp which are non-obvious to new programmers and often
- seasoned programmers as well.
-
- Common Pitfalls (Part 3):
-
- [3-0] Why does (READ-FROM-STRING "foobar" :START 3) return FOOBAR
- instead of BAR?
- [3-1] Why can't it deduce from (READ-FROM-STRING "foobar" :START 3)
- that the intent is to specify the START keyword parameter
- rather than the EOF-ERROR-P and EOF-VALUE optional parameters?
- [3-2] Why can't I apply #'AND and #'OR?
- [3-3] I used a destructive function (e.g. DELETE, SORT), but it
- didn't seem to work. Why?
- [3-4] After I NREVERSE a list, it's only one element long. After I
- SORT a list, it's missing things. What happened?
- [3-5] Why does (READ-LINE) return "" immediately instead of waiting
- for me to type a line?
- [3-6] I typed a form to the read-eval-print loop, but nothing happened. Why?
- [3-7] DEFMACRO doesn't seem to work.
- When I compile my file, LISP warns me that my macros are undefined
- functions, or complains "Attempt to call <function> which is
- defined as a macro.
- [3-8] Name conflict errors are driving me crazy! (EXPORT, packages)
- [3-9] Closures don't seem to work properly when referring to the
- iteration variable in DOLIST, DOTIMES and DO.
- [3-10] What is the difference between FUNCALL and APPLY?
- [3-11] Miscellaneous things to consider when debugging code.
- [3-12] When is it right to use EVAL?
- [3-13] Why does my program's behavior change each time I use it?
- [3-14] When producing formatted output in Lisp, where should you put the
- newlines (e.g., before or after the line, FRESH-LINE vs TERPRI,
- ~& vs ~% in FORMAT)?
- [3-15] I'm using DO to do some iteration, but it doesn't terminate.
-
- Search for [#] to get to question number # quickly.
-
- ----------------------------------------------------------------
- [3-0] Why does (READ-FROM-STRING "foobar" :START 3) return FOOBAR instead
- of BAR?
-
- READ-FROM-STRING is one of the rare functions that takes both &OPTIONAL and
- &KEY arguments:
-
- READ-FROM-STRING string &OPTIONAL eof-error-p eof-value
- &KEY :start :end :preserve-whitespace
-
- When a function takes both types of arguments, all the optional
- arguments must be specified explicitly before any of the keyword
- arguments may be specified. In the example above, :START becomes the
- value of the optional EOF-ERROR-P parameter and 3 is the value of the
- optional EOF-VALUE parameter.
-
- ----------------------------------------------------------------
- [3-1] Why can't it deduce from (READ-FROM-STRING "foobar" :START 3) that
- the intent is to specify the START keyword parameter rather than
- the EOF-ERROR-P and EOF-VALUE optional parameters?
-
- In Common Lisp, keyword symbols are first-class data objects. Therefore,
- they are perfectly valid values for optional parameters to functions.
- There are only four functions in Common Lisp that have both optional and
- keyword parameters (they are PARSE-NAMESTRING, READ-FROM-STRING,
- WRITE-LINE, and WRITE-STRING), so it's probably not worth adding a
- nonorthogonal kludge to the language just to make these functions slightly
- less confusing; unfortunately, it's also not worth an incompatible change
- to the language to redefine those functions to use only keyword arguments.
-
- ----------------------------------------------------------------
- [3-2] Why can't I apply #'AND and #'OR?
-
- Here's the simple, but not necessarily satisfying, answer: AND and OR are
- macros, not functions; APPLY and FUNCALL can only be used to invoke
- functions, not macros and special operators.
-
- OK, so what's the *real* reason? The reason that AND and OR are macros
- rather than functions is because they implement control structure in
- addition to computing a boolean value. They evaluate their subforms
- sequentially from left/top to right/bottom, and stop evaluating subforms as
- soon as the result can be determined (in the case of AND, as soon as a
- subform returns NIL; in the case of OR, as soon as one returns non-NIL);
- this is referred to as "short circuiting" in computer language parlance.
- APPLY and FUNCALL, however, are ordinary functions; therefore, their
- arguments are evaluated automatically, before they are called. Thus, were
- APPLY able to be used with #'AND, the short-circuiting would be defeated.
-
- Perhaps you don't really care about the short-circuiting, and simply want
- the functional, boolean interpretation. While this may be a reasonable
- interpretation of trying to apply AND or OR, it doesn't generalize to other
- macros well, so there's no obvious way to have the Lisp system "do the
- right thing" when trying to apply macros. The only function associated
- with a macro is its expander function; this function accepts and returns
- and form, so it cannot be used to compute the value.
-
- The Common Lisp functions EVERY and SOME can be used to get the
- functionality you intend when trying to apply #'AND and #'OR. For
- instance, the erroneous form:
-
- (apply #'and *list*)
-
- can be translated to the correct form:
-
- (every #'identity *list*)
-
- ----------------------------------------------------------------
- [3-3] I used a destructive function (e.g. DELETE, SORT), but it didn't seem to
- work. Why?
-
- I assume you mean that it didn't seem to modify the original list. There
- are several possible reasons for this. First, many destructive functions
- are not *required* to modify their input argument, merely *allowed* to; in
- some cases, the implementation may determine that it is more efficient to
- construct a new result than to modify the original (this may happen in Lisp
- systems that use "CDR coding", where RPLACD may have to turn a CDR-NEXT or
- CDR-NIL cell into a CDR-NORMAL cell), or the implementor may simply not
- have gotten around to implementing the destructive version in a truly
- destructive manner. Another possibility is that the nature of the change
- that was made involves removing elements from the front of a list; in this
- case, the function can simply return the appropriate tail of the list,
- without actually modifying the list. And example of this is:
-
- (setq *a* (list 3 2 1))
- (delete 3 *a*) => (2 1)
- *a* => (3 2 1)
-
- Similarly, when one sorts a list, SORT may destructively rearrange the
- pointers (cons cells) that make up the list. SORT then returns the cons
- cell that now heads the list; the original cons cell could be anywhere in
- the list. The value of any variable that contained the original head of the
- list hasn't changed, but the contents of that cons cell have changed
- because SORT is a destructive function:
-
- (setq *a* (list 2 1 3))
- (sort *a* #'<) => (1 2 3)
- *a* => (2 3)
-
- In both cases, the remedy is the same: store the result of the
- function back into the place whence the original value came, e.g.
-
- (setq *a* (delete 3 *a*))
- *a* => (2 1)
-
- Why don't the destructive functions do this automatically? Recall that
- they are just ordinary functions, and all Lisp functions are called by
- value. Therefore, these functions do not know where the lists they are
- given came from; they are simply passed the cons cell that represents the
- head of the list. Their only obligation is to return the new cons cell that
- represents the head of the list.
-
- One thing to be careful about when doing this is that the original list
- might be referenced from multiple places, and all of these places may need
- to be updated. For instance:
-
- (setq *a* (list 3 2 1))
- (setq *b* *a*)
- (setq *a* (delete 3 *a*))
- *a* => (2 1)
- *b* => (3 2 1) ; *B* doesn't "see" the change
- (setq *a* (delete 1 *a*))
- *a* => (2)
- *b* => (3 2) ; *B* sees the change this time, though
-
- One may argue that destructive functions could do what you expect by
- rearranging the CARs of the list, shifting things up if the first element
- is being deleted, as they are likely to do if the argument is a vector
- rather than a list. In many cases they could do this, although it would
- clearly be slower. However, there is one case where this is not possible:
- when the argument or value is NIL, and the value or argument, respectively,
- is not. It's not possible to transform the object referenced from the
- original cell from one data type to another, so the result must be stored
- back. Here are some examples:
-
- (setq *a* (list 3 2 1))
- (delete-if #'numberp *a) => NIL
- *a* => (3 2 1)
- (setq *a* nil *b* '(1 2 3))
- (nconc *a* *b*) => (1 2 3)
- *a* => NIL
-
- The names of most destructure functions (except for sort, delete,
- rplaca, rplacd, and setf of accessor functions) have the prefix N.
-
- In summary, the two common problems to watch out for when using
- destructive functions are:
-
- 1. Forgetting to store the result back. Even though the list
- is modified in place, it is still necessary to store the
- result of the function back into the original location, e.g.,
- (setq foo (delete 'x foo))
-
- If the original list was stored in multiple places, you may
- need to store it back in all of them, e.g.
- (setq bar foo)
- ...
- (setq foo (delete 'x foo))
- (setq bar foo)
-
- 2. Sharing structure that gets modified. If it is important
- to preserve the shared structure, then you should either
- use a nondestructive operation or copy the structure first
- using COPY-LIST or COPY-TREE.
- (setq bar (cdr foo))
- ...
- (setq foo (sort foo #'<))
- ;;; now it's not safe to use BAR
-
- Note that even nondestructive functions, such as REMOVE, and UNION,
- can return a result which shares structure with an argument.
- Nondestructive functions don't necessarily copy their arguments; they
- just don't modify them.
-
- ----------------------------------------------------------------
- [3-4] After I NREVERSE a list, it's only one element long. After I SORT
- a list, it's missing things. What happened?
-
- These are particular cases of the previous question. Many NREVERSE and
- SORT implementations operate by rechaining all the CDR links in the list's
- backbone, rather than by replacing the CARs. In the case of NREVERSE, this
- means that the cons cell that was originally first in the list becomes the
- last one. As in the last question, the solution is to store the result
- back into the original location.
-
- ----------------------------------------------------------------
- [3-5] Why does (READ-LINE) return "" immediately instead of waiting for
- me to type a line?
-
- Many Lisp implementations on line-buffered systems do not discard the
- newline that the user must type after the last right parenthesis in order
- for the line to be transmitted from the OS to Lisp. Lisp's READ function
- returns immediately after seeing the matching ")" in the stream. When
- READLINE is called, it sees the next character in the stream, which is a
- newline, so it returns an empty line. If you were to type "(read-line)This
- is a test" the result would be "This is a test".
-
- The simplest solution is to use (PROGN (CLEAR-INPUT) (READ-LINE)). This
- discards the buffered newline before reading the input. However, it would
- also discard any other buffered input, as in the "This is a test" example
- above; some implementation also flush the OS's input buffers, so typeahead
- might be thrown away.
-
- ----------------------------------------------------------------
- [3-6] I typed a form to the read-eval-print loop, but nothing happened. Why?
-
- There's not much to go on here, but a common reason is that you haven't
- actually typed a complete form. You may have typed a doublequote, vertical
- bar, "#|" comment beginning, or left parenthesis that you never matched
- with another doublequote, vertical bar, "|#", or right parenthesis,
- respectively. Try typing a few right parentheses followed by Return.
-
- ----------------------------------------------------------------
- [3-7] DEFMACRO doesn't seem to work.
- When I compile my file, LISP warns me that my macros are undefined
- functions, or complains "Attempt to call <function> which is
- defined as a macro.
-
- When you evaluate a DEFMACRO form or proclaim a function INLINE, it
- doesn't go back and update code that was compiled under the old
- definition. When redefining a macro, be sure to recompile any
- functions that use the macro. Also be sure that the macros used in a
- file are defined before any forms in the same file that use them.
-
- Certain forms, including LOAD, SET-MACRO-CHARACTER, and
- REQUIRE, are not normally evaluated at compile time. Common Lisp
- requires that macros defined in a file be used when compiling later
- forms in the file. If a Lisp doesn't follow the standard, it may be
- necessary to wrap an EVAL-WHEN form around the macro definition.
-
- Most often the "macro was previously called as a function" problem
- occurs when files were compiled/loaded in the wrong order. For
- example, developers may add the definition to one file, but use it in
- a file which is compiled/loaded before the definition. To work around
- this problem, one can either fix the modularization of the system, or
- manually recompile the files containing the forward references to macros.
-
- Also, if your macro calls functions at macroexpand time, those functions
- may need to be in an EVAL-WHEN. For example,
-
- (defun some-function (x)
- x)
-
- (defmacro some-macro (y)
- (let ((z (some-function y)))
- `(print ',z)))
-
- If the macros are defined in a file you require, make sure your
- require or load statement is in an appropriate EVAL-WHEN. Many people
- avoid all this nonsense by making sure to load all their files before
- compiling them, or use a system facility (or just a script file) that
- loads each file before compiling the next file in the system.
-
- ----------------------------------------------------------------
- [3-8] Name conflict errors are driving me crazy! (EXPORT, packages)
-
- If a package tries to export a symbol that's already defined, it will
- report an error. You probably tried to use a function only to discover
- that you'd forgotten to load its file. The failed attempt at using the
- function caused its symbol to be interned. So now, when you try to
- load the file, you get a conflict. Unfortunately, understanding and
- correcting the code which caused the export problem doesn't make those
- nasty error messages go away. That symbol is still interned where it
- shouldn't be. Use unintern to remove the symbol from a package before
- reloading the file. Also, when giving arguments to REQUIRE or package
- functions, use strings or keywords, not symbols: (find-package "FOO"),
- (find-package :foo).
-
- A sometimes useful technique is to rename (or delete) a package
- that is "too messed up". Then you can reload the relevant files
- into a "clean" package.
-
- ----------------------------------------------------------------
- [3-9] Closures don't seem to work properly when referring to the
- iteration variable in DOLIST, DOTIMES and DO.
-
- DOTIMES, DOLIST, and DO all use assignment instead of binding to
- update the value of the iteration variables. So something like
-
- (let ((l nil))
- (dotimes (n 10)
- (push #'(lambda () n)
- l)))
-
- will produce 10 closures over the same value of the variable N.
- ----------------------------------------------------------------
- [3-10] What is the difference between FUNCALL and APPLY?
-
- FUNCALL is useful when the programmer knows the length of the argument
- list, but the function to call is either computed or provided as a
- parameter. For instance, a simple implementation of MEMBER-IF (with
- none of the fancy options) could be written as:
-
- (defun member-if (predicate list)
- (do ((tail list (cdr tail)))
- ((null tail))
- (when (funcall predicate (car tail))
- (return-from member-if tail))))
-
- The programmer is invoking a caller-supplied function with a known
- argument list.
-
- APPLY is needed when the argument list itself is supplied or computed.
- Its last argument must be a list, and the elements of this list become
- individual arguments to the function. This frequently occurs when a
- function takes keyword options that will be passed on to some other
- function, perhaps with application-specific defaults inserted. For
- instance:
-
- (defun open-for-output (pathname &rest open-options)
- (apply #'open pathname :direction :output open-options))
-
- FUNCALL could actually have been defined using APPLY:
-
- (defun funcall (function &rest arguments)
- (apply function arguments))
-
- ----------------------------------------------------------------
- [3-11] Miscellaneous things to consider when debugging code.
-
- This question lists a variety of problems to watch out for when
- debugging code. This is sort of a catch-all question for problems too
- small to merit a question of their own. See also question [1-2] for
- some other common problems.
-
- Functions:
-
- * (flet ((f ...)) (eq #'f #'f)) can return false.
-
- * The function LIST-LENGTH is not a faster, list-specific version
- of the sequence function LENGTH. It is list-specific, but it's
- slower than LENGTH because it can handle circular lists.
-
- * Don't confuse the use of LISTP and CONSP. CONSP tests for the
- presence of a cons cell, but will return NIL when called on NIL.
- LISTP could be defined as (defun listp (x) (or (null x) (consp x))).
-
- * Use the right test for equality:
- EQ tests if the objects are identical -- numbers with the
- same value need not be EQ, nor are two similar lists
- necessarily EQ. Similarly for characters and strings.
- For instance, (let ((x 1)) (eq x x)) is not guaranteed
- to return T.
- EQL Like EQ, but is also true if the arguments are numbers
- of the same type with the same value or character objects
- representing the same character. (eql -0.0 0.0) is not
- guaranteed to return T.
- EQUAL Tests if the arguments are structurally isomorphic, using
- EQUAL to compare components that conses, arrays, strings
- or pathnames, and EQ for all other data objects
- (except for numbers and characters, which are compared
- using EQL).
- EQUALP Like EQUAL, but ignores type differences when comparing
- numbers and case differences when comparing characters.
- = Compares the values of two numbers even if they are of
- different types.
- CHAR= Case-sensitive comparison of characters.
- CHAR-EQUAL Case-insensitive comparison of characters.
- STRING= Compares two strings, checking if they are identical.
- It is case sensitive.
- STRING-EQUAL Like STRING=, but case-insensitive.
-
- * Some destructive functions that you think would modify CDRs might
- modify CARs instead. (E.g., NREVERSE.)
-
- * READ-FROM-STRING has some optional arguments before the
- keyword parameters. If you want to supply some keyword
- arguments, you have to give all of the optional ones too.
-
- * If you use the function READ-FROM-STRING, you should probably bind
- *READ-EVAL* to NIL. Otherwise an unscrupulous user could cause a
- lot of damage by entering
- #.(shell "cd; rm -R *")
- at a prompt.
-
- * Only functional objects can be funcalled in CLtL2, so a lambda
- expression '(lambda (..) ..) is no longer suitable. Use
- #'(lambda (..) ..) instead. If you must use '(lambda (..) ..),
- coerce it to type FUNCTION first using COERCE.
-
- Methods:
-
- * PRINT-OBJECT methods can make good code look buggy. If there is a
- problem with the PRINT-OBJECT methods for one of your classes, it
- could make it seem as though there were a problem with the object.
- It can be very annoying to go chasing through your code looking for
- the cause of the wrong value, when the culprit is just a bad
- PRINT-OBJECT method.
-
- Initialization:
-
- * Don't count on array elements being initialized to NIL, if you don't
- specify an :initial-element argument to MAKE-ARRAY. For example,
- (make-array 10) => #(0 0 0 0 0 0 0 0 0 0)
-
- Iteration vs closures:
-
- * DO and DO* update the iteration variables by assignment; DOLIST and
- DOTIMES are allowed to use assignment (rather than a new binding).
- (All CLtL1 says of DOLIST and DOTIMES is that the variable "is
- bound" which has been taken as _not_ implying that there will be
- separate bindings for each iteration.)
-
- Consequently, if you make closures over an iteration variable
- in separate iterations they may nonetheless be closures over
- the same variable and hence will all refer to the same value
- -- whatever value the variable was given last. For example,
- (let ((fns '()))
- (do ((x '(1 2) (cdr x)))
- ((null x))
- (push #'(lambda () x)
- fns))
- (mapcar #'funcall (reverse fns)))
- returns (nil nil), not (1 2), not even (2 2). Thus
- (let ((l nil))
- (dolist (a '(1 2 3) l)
- (push #'(lambda () a)
- l)))
- returns a list of three closures closed over the same bindings, whereas
- (mapcar #'(lambda (a) #'(lambda () a)) '(1 2 3))
- returns a list of closures over distinct bindings.
-
- Defining Variables and Constants:
-
- * (defvar var init) assigns to the variable only if it does not
- already have a value. So if you edit a DEFVAR in a file and
- reload the file only to find that the value has not changed,
- this is the reason. (Use DEFPARAMETER if you want the value
- to change upon reloading.) DEFVAR is used to declare a variable
- that is changed by the program; DEFPARAMETER is used to declare
- a variable that is normally constant, but which can be changed
- to change the functioning of a program.
-